package com.gkzf.ai.module.crm.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.gkzf.ai.module.crm.util.HtmlTempkateCommonMethod.mapConvertList;

@Slf4j
public class ExcelTemplateParser {

    // 最终的文本模板，包含 {} 占位符。
    // 占位符名称需要与模板定义Excel中占位符定义行的内容（去除花括号后）一致。
    private static final String FINAL_REPORT_TEMPLATE = """
===== 个人信用报告概览 (通过双Excel解析) =====

报告基本信息:
  被查询者姓名:{name}
  被查询者证件类型:{idNumberType}
  被查询者证件号码:{idNumber}
  查询机构:{local}
  查询原因:{localQuery}

个人基本信息 (身份信息):
  性别:{gender}
  出生日期:{date_of_birth}
  婚姻状况:{marital_status}
  就业状况:{employment_status}
// ... 根据你的需求添加其他占位符，只要它们在模板定义Excel的占位符定义行中出现

========================================
""";

    // 正则表达式用于提取占位符名称，如从 "{name}" 中提取 "name"
    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{([^}]+)\\}");
    // 自定义表头 本信息人表头
    private static final Map<String, String> LOCALT_INFO = new HashMap<>();
    // 基本信息表头
    private static final Map<String, String> BASIC_INFO = new HashMap<>();
    // 循环贷账户
    private static final Map<String, String> REVOLVING_LOAN_ACCOUNT = new HashMap<>();

    // 贷记卡账户
    private static final Map<String, String> CREDIT_CARD_ACCOUNT = new HashMap<>();

    // 账户明细
    private static final Map<String, String> ACCOUNT_DETAILS = new HashMap<>();
    static {
        LOCALT_INFO.put("被查询者姓名", "1");
        LOCALT_INFO.put("被查询者证件类型", "1");
        LOCALT_INFO.put("被查询者证件号码", "1");
        LOCALT_INFO.put("查询机构", "1");
        LOCALT_INFO.put("查询原因", "1");
        // 身份信息
        BASIC_INFO.put("性别", "1");
        BASIC_INFO.put("出生日期", "1");
        BASIC_INFO.put("婚姻状况", "1");
        BASIC_INFO.put("就业状况", "1");
        BASIC_INFO.put("学历", "1");
        BASIC_INFO.put("学位", "1");
        BASIC_INFO.put("国籍", "1");
        BASIC_INFO.put("电子邮箱", "1");
        // 非循环贷账户
        REVOLVING_LOAN_ACCOUNT.put("管理机构数","1");
        REVOLVING_LOAN_ACCOUNT.put("账户数","1");
        REVOLVING_LOAN_ACCOUNT.put("授信总额","1");
        REVOLVING_LOAN_ACCOUNT.put("余额","1");
        REVOLVING_LOAN_ACCOUNT.put("最近6个月平均应还款","1");
        // 贷记卡
        CREDIT_CARD_ACCOUNT.put("发卡机构数","1");
        CREDIT_CARD_ACCOUNT.put("账户数","1");
        CREDIT_CARD_ACCOUNT.put("授信总额","1");
        CREDIT_CARD_ACCOUNT.put("单家机构最高授信额","1");
        CREDIT_CARD_ACCOUNT.put("单家机构最低授信额","1");
        CREDIT_CARD_ACCOUNT.put("已用额度","1");
        CREDIT_CARD_ACCOUNT.put("最近6个月平均使用额度","1");
        // 贷款明细
        ACCOUNT_DETAILS.put("管理机构","1");
        ACCOUNT_DETAILS.put("账户标识","1");
        ACCOUNT_DETAILS.put("管理机构","1");
        ACCOUNT_DETAILS.put("管理机构","1");
        ACCOUNT_DETAILS.put("管理机构","1");
        ACCOUNT_DETAILS.put("管理机构","1");
        // 如果有不在这个表格中的固定信息，需要单独处理或定义不同的映射方式
    }
    /**
     * 从Excel文件中读取数据（基于表头、占位符行和数据行的结构），并填充到文本模板中。
     *
     * @param dataExcelFilePath 数据Excel文件的路径
     * @return 填充数据后的报告字符串
     * @throws IOException 如果读取Excel文件发生错误
     * @throws IllegalArgumentException 如果文件格式不支持，或找不到必要的行/表头
     */
    public List<Map<String, String>> parseExcelsAndFillTemplate(
            String dataExcelFilePath) throws IOException {
        List<Map<String, String>> data = new ArrayList<>();
        try (FileInputStream fis = new FileInputStream(new File(dataExcelFilePath));
             Workbook workbook = getWorkbook(fis, dataExcelFilePath)) {
            Sheet sheet = workbook.getSheetAt(0);
            for (Row row : sheet) {
                Map<String, String> map = new LinkedHashMap<>();
                for (Cell placeholderCell : row) {
                    switch (placeholderCell.getCellType()) {
                        case STRING:
                            map.put(row.getRowNum()+":"+placeholderCell.getColumnIndex()+"_"+placeholderCell.getStringCellValue(),"0");
                            break;
                        case NUMERIC:
                            map.put(row.getRowNum()+":"+placeholderCell.getColumnIndex()+"_"+placeholderCell.getNumericCellValue(),"0");
                            break;
                    }

                }
                data.add(map);
            }
        }
        return data;
    }

    /**
     * Helper method to get the correct Workbook instance based on file extension.
     */
    private Workbook getWorkbook(FileInputStream fis, String filePath) throws IOException, IllegalArgumentException {
        if (filePath.toLowerCase().endsWith(".xlsx")) {
            return new XSSFWorkbook(fis);
        } else if (filePath.toLowerCase().endsWith(".xls")) {
            return new HSSFWorkbook(fis);
        } else {
            throw new IllegalArgumentException("Unsupported file format for Excel: " + filePath + ". Only .xls and .xlsx are supported.");
        }
    }


    /**
     * 将数据map中的行号去除
     * @param dataMap
     * @return
     */
    public static Map<String,String> convertMap(Map<String, String> dataMap){
        Map<String,String> resultMap = new HashMap<>();
        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
            if (entry.getKey().contains("_") && entry.getValue().contains("_")) {
                String[] key = entry.getKey().split("_");
                String[] value = entry.getValue().split("_");
                if (key.length > 1 && value.length > 1) {
                    resultMap.put(key[1], value[1]);
                }
            }
        }
        return resultMap;
    }

    /**
     * 根据标题和数据表头，获取数据表头对应的数据
     * @param titleMap 表头Map
     * @param dataMap  数据Map
     * @return
     */
    public static Map<String,String> dataCorrespondingAcquisition(Map<String,String> titleMap,Map<String,String> dataMap){
        List<String> titleMapList = mapConvertList(titleMap);
        Map<String,String>  resultMap = new HashMap<>();
        Map<String,String> valueMap = convertMap(dataMap);
        for (int i = 0; i < titleMapList.size(); i++) {
            String key = titleMapList.get(i);
            String value = valueMap.get(key);
            resultMap.put(key,Optional.ofNullable(value).orElse("0"));
        }
        return resultMap;
    }

    /**
     * 判断是否包含key
     * @param titleMap 表头Map
     * @param key  数据Map
     * @return
     */
    public static boolean verifyIdContainKey(Map<String,String> titleMap,String key){
        return titleMap.entrySet().stream().anyMatch(    item -> item.getKey().contains(key));

    }

    /**
     * 根据标题，获取数据表头对应的数据
     * @param titleMap 表头Map
     * @param dataMap  数据Map
     * @param finalReport 最终报告集合
     * @param i 最终报告集合索引
     * @return 对应 ${titleMap} 的数据
     */
    public static Map<String,String> dataCorrespondingTraversal(Map<String,String> titleMap,Map<String,String> dataMap,List<Map<String,String>> finalReport,int i){
        // 遍历titleMap 表头
        Map<String, String>  localInfoMap = null;
        Set<Map.Entry<String, String>> localtInfoSet = titleMap.entrySet();
        for (Map.Entry<String, String> entry : localtInfoSet) {
            boolean isKey = verifyIdContainKey(dataMap,entry.getKey());
            if (isKey){
                Map<String,String> storageMap = new HashMap<>();
                Map<String, String> map = finalReport.get(i + 1);
                List<String> storageList = mapConvertList(dataMap);
                List<String> storageDataList = mapConvertList(map);
                if (storageDataList.size() == storageList.size()) {
                    for (int j = 0; j < storageList.size(); j++) {
                        String key = storageList.get(j);
                        String value = storageDataList.get(j);
                        storageMap.put(key.replace("\n", "").replace("\r", ""), value.replace("\n", "").replace("\r", ""));
                    }
                }
                localInfoMap = dataCorrespondingAcquisition(titleMap, storageMap);
            }
        }
        return localInfoMap;
    }

    /**
     *  解析 贷记卡 非循环贷  循环贷一 循环贷二 汇总信息
     */
    public static void anaysisSummaryLoanInformation(AtomicInteger atomicInteger,
                                                     int number,
                                                     int nextNumber,
                                                     int i,
                                                     String title,
                                                     Map<String, String> storageMap,
                                                     Map<String,Object> finallyMap,
                                                     Map<String,String> map,
                                                     Map<String, String> titleMap,
                                                     List<Map<String,String>> finalReport){
        // 判断是否到非循环贷账户
        if(atomicInteger.get() == number) {
            // 判断是否是非循环贷账户
            String spouseInformation =  title;
            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (entry.getKey().contains(spouseInformation)){
                    atomicInteger.incrementAndGet();
                    continue;
                }
            }
        }
        if (atomicInteger.get() == nextNumber) {
            Map<String, String> stringMap = dataCorrespondingTraversal(titleMap, map, finalReport, i);
            if (Objects.nonNull(stringMap) && !stringMap.isEmpty()){
                for (Map.Entry<String, String> entry : stringMap.entrySet()) {
                    if (StringUtils.isNotBlank(entry.getValue())){
                        storageMap.put(entry.getKey(),entry.getValue());
                    }
                }
                atomicInteger.incrementAndGet();
                finallyMap.put(title, JSON.toJSONString(storageMap));
                storageMap.clear();

            }
        }
    }

    // 用于检查四位数字年份的正则表达式
    private static final Pattern YEAR_PATTERN = Pattern.compile("\\d{4}");

    // 假设你有一个 isPositiveInteger 方法 (如果 Integer.parseInt() 失败则返回 false)
    private static boolean isPositiveInteger(String s) {
        if (s == null || s.trim().isEmpty()) {
            return false;
        }
        try {
            int i = Integer.parseInt(s.trim());
            return i > 0; // 正整数
        } catch (NumberFormatException e) {
            return false;
        }
    }



    /**
     * 判断给定的 Element (假设是 table) 是否是还款记录Table的三种格式之一。
     * @param table 要判断的 Jsoup Table Element。
     * @return 如果匹配任一还款记录 Table 格式，返回 true；否则返回 false。
     */
    public static boolean verifyIsRepayment(Element table) {
        // 如果传入的 Element 为空或不是 table 标签，直接返回 false
        if (table == null || !table.tagName().equalsIgnoreCase("table")) {
            return false;
        }

        Elements rows = table.select("tr");

        // 至少需要一行来判断格式
        if (rows.isEmpty()) {
            return false;
        }

        // --- 检查格式 1 (年份 header) ---
        // 格式 1 需要至少 2 行 (header + 数据)
        // 特征: 第一行第一个 td 是 "年份"，且第一行有 >= 13 个 td (年份 + 12个月)
        // 附加检查: 第二行（第一个数据行）的第一个 td 看起来像一个年份 (四位数字)
        if (rows.size() >= 2) {
            Element firstRow = rows.get(0);
            Elements headerTds = firstRow.select("td");
            if (headerTds.size() >= 10 && "年份".equals(headerTds.first().text().trim())) {
                // 检查第二行是否是年份数据行
                Element secondRow = rows.get(1);
                Elements secondRowTds = secondRow.select("td");
                if (!secondRowTds.isEmpty()) { // 确保至少有第一个 td
                    Matcher matcher = YEAR_PATTERN.matcher(secondRowTds.first().text().trim());
                    if (matcher.matches()) {
                        return true; // 匹配格式 1
                    }
                }
            }
        }

        // --- 检查格式 3 (空 header + 数字月份) ---
        // 格式 3 需要至少 3 行 (header + 两行数据)
        // 特征: 第一行第一个 td 为空，后续 12 个 td 是正整数，且第一行有 >= 13 个 td
        // 附加检查: 第二行（第一个数据行）的第一个 td 看起来像一个年份，第三行（第二个数据行）的第一个 td 为空
        if (rows.size() >= 3) {
            Element firstRow = rows.get(0);
            Elements headerTds = firstRow.select("td");
            if (headerTds.size() >= 13 && firstRow.text().trim().isEmpty()) {
                int numberCount = 0;
                // 检查后续 12 个 td 是否是正整数 (对应月份 1-12)
                for (int j = 1; j < 13; j++) {
                    // 防止索引越界
                    if (j < headerTds.size() && isPositiveInteger(headerTds.get(j).text().trim())) {
                        numberCount++;
                    }
                }
                // 如果至少有 12 个 td 是正整数
                if (numberCount >= 10) {
                    // 检查第二行和第三行的结构
                    Element secondRow = rows.get(1);
                    Element thirdRow = rows.get(2);
                    Elements secondRowTds = secondRow.select("td");
                    Elements thirdRowTds = thirdRow.select("td");

                    // 确保行有足够的列，且开头 td 符合预期
                    if (!secondRowTds.isEmpty() && YEAR_PATTERN.matcher(secondRowTds.first().text().trim()).matches() &&
                            !thirdRowTds.isEmpty() && thirdRowTds.first().text().trim().isEmpty()) {
                        log.info("  Confirmed Format 3.");
                        return true; // 匹配格式 3
                    }
                }
            }
        }


        // --- 检查格式 2 (Fallback, 数据 td 中包含 <br>) ---
        // 如果不符合格式 1 或格式 3，则可能是格式 2
        // 格式 2 的数据行通常以年份开头，且数据 td 中包含 <br>
        // 我们检查前几行（例如前 2 行，因为数据可能从第 0 或第 1 行开始）
        // 如果某一行包含 >= 13 个 td，且其数据 td (索引 1-12) 中有足够的 td 包含 <br> (比如超过一半)，则认为是格式 2

        int rowsToCheck = Math.min(rows.size(), 2); // 只检查前两行（索引 0 和 1）作为代表
        for (int i = 0; i < rowsToCheck; i++) {
            Element dataRow = rows.get(i);
            Elements dataTds = dataRow.select("td");

            // 确保行有足够的列 (至少 13 个: 年份 + 12个月)
            if (dataTds.size() >= 13) {
                int brCount = 0;
                // 检查数据 td (索引 1 到 12)
                for (int j = 1; j < 13; j++) {
                    if (j < dataTds.size()) { // 防止索引越界
                        String tdHtml = dataTds.get(j).html(); // 获取包含 <br> 的内部 HTML
                        if (tdHtml.contains("<br>")) {
                            brCount++;
                        }
                    }
                }

                // 如果有很多 td 包含 <br> (例如超过半数，这里用 >= 6)
                if (brCount >= 6) { // 阈值可以根据实际数据调整
                    return true; // 匹配格式 2
                }
            } else {
            }
        }

        // 如果没有匹配任何已知格式
        return false;
    }

}
